<?php
// +----------------------------------------------------------------------
// | B5Yii2CMF V3.0 [快捷通用基础管理开发平台]
// +----------------------------------------------------------------------
// | Author: 冰舞 <357145480@qq.com>
// +----------------------------------------------------------------------
declare (strict_types=1);

namespace api\modules\admin\models;

use api\utils\libs\TraitToken;
use common\helpers\Functions;
use common\models\system\Admin;
use common\models\system\LoginLog;
use Yii;
use yii\base\Model;


class LoginForm extends Model
{
    use TraitToken;

    public string $error = '';
    public string $user_name;
    public string $password;
    public string $captchaToken;
    public $captchaData;
    public string $plat = 'web';
    public string $type = 'admin';

    private string $_token = '';
    private ?Admin $_user = null;

    /**
     * {@inheritdoc}
     */
    public function rules(): array
    {
        return [
            [['user_name', 'password', 'captchaToken'], 'required'],
            [['captchaData', 'plat', 'type'], 'safe']
        ];
    }

    public function attributeLabels(): array
    {
        return [
            'user_name' => '用户名',
            'password' => '密码',
            'captchaToken' => '滑块验证凭证',
        ];
    }

    /**
     * 用户登录
     */
    public function login(): string
    {
        if (!$this->validate()) {
            $this->error = Functions::getModelError($this);
        } else if (!$this->verifyCaptcha()) {
            $this->error = '滑块验证失败，请重新验证';
        } else {
            $user = $this->getUser();
            if (!$user || $user['password'] !== Admin::encryptPassword($this->password)) {
                $this->error = '用户名或密码错误';
            } else if ($user['status'] != 1) {
                $this->error = '用户已被禁用，无法登录';
            } else {
                $this->_token = $this->setToken($user['id'], $this->type, $this->plat);
                if (!$this->_token) $this->error = '登录保存失败';
            }
        }
        $token = $this->error ? '' : $this->_token;
        LoginLog::logAdd($this->user_name, $this->plat, $this->type, $token ? 1 : 0, $token ? '登录成功' : ($this->error ?: '登录失败'));
        return $token;
    }
    
    /**
     * 验证滑块验证码
     * @return bool
     */
    private function verifyCaptcha(): bool
    {
        if (empty($this->captchaToken)) {
            return false;
        }
        
        // 从前端传来的captchaData中提取信息
        if (!is_array($this->captchaData)) {
            return false;
        }
        
        // 检查是否已验证
        $verified = $this->captchaData['verified'] ?? false;
        if (!$verified) {
            return false;
        }
        
        $timestamp = $this->captchaData['timestamp'] ?? 0;
        
        // 解码token
        $decoded = base64_decode($this->captchaToken);
        if (!$decoded) {
            return false;
        }
        
        $parts = explode('_', $decoded);
        if (count($parts) < 1) {
            return false;
        }
        
        $tokenTimestamp = isset($parts[0]) ? (int)$parts[0] : 0;
        
        // 检查时间戳是否在合理范围内（5分钟内）
        if (time() - intval($timestamp / 1000) > 300) {
            return false;
        }
        
        // 验证token和timestamp一致性
        if (abs($tokenTimestamp - $timestamp) > 1000) {
            return false;
        }
        
        // 验证token只能使用一次（防止重放攻击）
        $session = Yii::$app->session;
        $usedKey = 'slider_used_' . md5($this->captchaToken);
        if ($session->get($usedKey)) {
            return false;
        }
        
        // 标记token已使用
        $session->set($usedKey, true);
        
        return true;
    }

    /**
     * @param $id
     * @return Admin|null
     */
    protected function getUser($id = null): ?Admin
    {
        if ($this->_user === null) {
            if ($id) {
                $this->_user = Admin::findOne($id);
            } elseif ($this->user_name) {
                $this->_user = Admin::findOne(['user_name' => $this->user_name]);
            }
        }
        return $this->_user;
    }
}
